#include "Vector2.h"

const Vector2<float> Vector2<float>::ZERO( 0, 0 );
const Vector2<float> Vector2<float>::UNIT_X( 1, 0 );
const Vector2<float> Vector2<float>::UNIT_Y( 0, 1 );

template <class Real>
Vector2<Real>::Vector2()
{
	// uninitialized
}

template <class Real>
Vector2<Real>::Vector2(Real mx, Real my)
{
	x = mx;
	y = my;
}

template <class Real>
Vector2<Real>::Vector2(const Vector2<Real> &vec)
{
	x = vec.x;
	y = vec.y;
}

template<class Real>
Real& Vector2<Real>::operator [] ( int i ) const
{
	return ( Real& ) *( &x + i );
}

template<class Real>
Vector2<Real>& Vector2<Real>::operator = ( const Vector2<Real>& vec )
{
	x = vec.x;
	y = vec.y;

	return *this;
}

template<class Real>
bool Vector2<Real>::operator == ( const Vector2<Real>& vec ) const
{
	return  ( x != vec.x || y != vec.x );
}

template<class Real>
Vector2<Real>& Vector2<Real>::operator + ( const Vector2<Real>& vec ) const
{
	Vector2 sum;
	sum.x = x + vec.x;
	sum.y = y + vec.y;

	return sum;
}

template<class Real>
Vector2<Real>& Vector2<Real>::operator -(const Vector2<Real> &vec) const
{
	Vector2<Real> diff;
	diff.x = x - vec.x;
	diff.y = y - vec.y;
	
	return diff;
}

template<class Real>
Vector2<Real>& Vector2<Real>::operator *( Real s ) const
{
	Vector2<Real> prod;
	prod.x = s * vec.x;
	prod.y = s * vec.y;
	
	return prod;
}

template<class Real>
Vector2<Real>& Vector2<Real>::operator -() const
{
	Vector2<Real> neg;
	neg.x = -x;
	neg.y = -y;
	return neg;
}

template<class Real>
Vector2<Real>& Vector2<Real>::operator+= ( const Vector2<Real>& vec ) const
{
	x += vec.x;
	y += vec.y;
}

template<class Real>
Vector2<Real>& Vector2<Real>::operator-= ( const Vector2<Real>& vec ) const
{
	x -= vec.x;
	y -= vec.y;
}

template<class Real>
Vector2<Real>& Vector2<Real>::operator*= ( const Vector2<Real>& vec ) const
{
	x *= vec.x;
	y *= vec.y;
	return *this;
}

template<class Real>
Real Vector2<Real>::squared_length( ) const
{
	return x*x + y*y;
}

template<class Real>
Real Vector2<Real>::dot( const Vector2<Real>& vec ) const
{
	return x*vec.x + y*vec.y;
}

template<class Real>
Vector2<Real>& Vector2<Real>::operator / ( Real s ) const
{
	Vector2 quot;

	if ( s != 0.0 )
	{
		Real inv_scalar = 1.0 / s;
		quot.x = inv_scalar*x;
		quot.y = inv_scalar*y;
		return quot;
	}
	else
	{
		return Vector2( Math::INFINITY, Math::INIFINITY );
	}
}

template<class Real>
Vector2<Real>& Vector2<Real>::operator /= ( Real s ) 
{
	if ( s != 0.0 )
	{
		Real inv_scalar = 1.0 / s;
		x *= inv_scalar;
		y *= inv_scalar;
	}
	else
	{
		x = Math::INFINITY;
		y = Math::INIFINITY;
	}
	return *this;
}

template<class Real>
Vector2<Real> Vector2<Real>::perp() const
{
	return Vector2( this.y, -this.x );
}

template<class Real>
Vector2<Real> Vector2<Real>::unit_perp() const
{
	Vector2 mp( y, -x );
	mp.unitize();
	return mp;
}

template<class Real>
Real Vector2<Real>::length() const
{
	return Math::sqrt( x*x + y*y );
}

template<class Real>
Real Vector2<Real>::unitize( Real tol )
{
	Real len = length();

	if ( len > tol )
	{
		Real inv_length = 1.0 / len;
		x *= inv_length;
		y *= inv_length;
	}
	else
	{
		len = 0.0;
	}
}

template<class Real>
Real Vector2<Real>::cross( const Vector2<Real>& vec ) const
{
	Real cross;

	cross = x*vec.y - y*vec.x;
	return cross;
}

template<class Real>
Vector2<Real> Vector2<Real>::unit_cross( const Vector2<Real>& vec ) const
{
	Vector2 cr;

	cr = ::cross( vec );
	cr.unitize();
}

template<class Real>
void Vector2<Real>::orthonormalize( Vector2<Real>& u, Vector2<Real>& v )
{
	u.unitize();

	Real fd = u.dot( v );
	v -= fd * u;
	v.unitize();
}

template<class Real>
void Vector2<Real>::generate_orthonormal_basis( Vector2<Real>& u, Vector2<Real>& v, bool unit_length )
{
	if ( unit_length )
		v.unitize();

	u = v.prep( );
}